function! s:lsp_variables() abort
    let g:lsp_auto_enable = 1
    let g:lsp_use_native_client = 0                            
    let g:lsp_preview_keep_focus = 1                        
    let g:lsp_preview_float = 1
    let g:lsp_preview_autoclose = 1                            
    " let g:lsp_preview_doubletap                            
    " let g:lsp_insert_text_enabled                          
    " let g:lsp_text_edit_enabled                            
    " let g:lsp_completion_documentation_enabled             
    " let g:lsp_completion_documentation_delay               
    " let g:lsp_diagnostics_enabled                          
    " let g:lsp_diagnostics_echo_cursor                      
    " let g:lsp_diagnostics_echo_delay                       
    " let g:lsp_diagnostics_float_cursor                     
    " let g:lsp_diagnostics_float_delay                      
    " let g:lsp_diagnostics_float_insert_mode_enabled        
    " let g:lsp_diagnostics_highlights_enabled               
    " let g:lsp_diagnostics_highlights_insert_mode_enabled   
    " let g:lsp_diagnostics_highlights_delay                 
    " let g:lsp_diagnostics_signs_enabled                    
    " let g:lsp_diagnostics_signs_insert_mode_enabled        
    " let g:lsp_diagnostics_signs_delay                      
    " let g:lsp_diagnostics_signs_priority                   
    " let g:lsp_diagnostics_signs_priority_map               
    " let g:lsp_diagnostics_virtual_text_enabled             
    " let g:lsp_diagnostics_virtual_text_insert_mode_enabled 
    " let g:lsp_diagnostics_virtual_text_delay               
    " let g:lsp_diagnostics_virtual_text_align               
    " let g:lsp_diagnostics_virtual_text_padding_left        
    " let g:lsp_diagnostics_virtual_text_wrap                
    " let g:lsp_document_code_action_signs_enabled           
    " let g:lsp_document_code_action_signs_delay             
    " let g:lsp_inlay_hints_enabled                          
    " let g:lsp_inlay_hints_delay                            
    " let g:lsp_inlay_hints_mode                             
    " let g:lsp_tree_incoming_prefix                         
    " let g:lsp_format_sync_timeout                          
    " let g:lsp_use_event_queue                              
    " let g:lsp_max_buffer_size                              
    " let g:lsp_document_highlight_enabled                   
    " let g:lsp_document_highlight_delay                     
    " let g:lsp_get_supported_capabilities                   
    " let g:lsp_document_symbol_detail                       
    " let g:lsp_peek_alignment                               
    " let g:lsp_preview_max_width                            
    " let g:lsp_preview_max_height                           
    " let g:lsp_preview_fixup_conceal                        
    " let g:lsp_float_max_width                              
    " let g:lsp_signature_help_enabled                       
    " let g:lsp_fold_enabled                                 
    " let g:lsp_hover_conceal                                
    " let g:lsp_hover_ui                                     
    " let g:lsp_ignorecase                                   
    " let g:lsp_log_file                                     
    " let g:lsp_log_verbose                                  
    " let g:lsp_semantic_enabled                             
    " let g:lsp_semantic_delay                               
    " let g:lsp_text_document_did_save_delay                 
    " let g:lsp_snippet_expand                               
    " let g:lsp_completion_resolve_timeout                   
    " let g:lsp_tagfunc_source_methods                       
    " let g:lsp_show_message_request_enabled                 
    " let g:lsp_work_done_progress_enabled                   
    " let g:lsp_show_message_log_level                       
    " let g:lsp_untitled_buffer_enabled                      
endfunction

function! s:lsp_settings() abort
    let g:lsp_settings = {}
    let g:lsp_settings_enable_suggestions = 1
    if has("win32")
        let g:lsp_settings_servers_dir = "~/AppData/Local/vim-lsp-settings/servers"
    else
        let g:lsp_settings_servers_dir = "~/.local/share/vim-lsp-settings/servers"
    endif
    let g:lsp_settings_global_settings_dir = ""
    let g:lsp_settings_deny_local_keys = [ "cmd" ]
    " let g:lsp_settings_filetype_xxx
endfunction

function! s:lsp_autocmds() abort
        augroup lsp_install
            au!
            " call s:on_lsp_buffer_enabled only for languages that has the server registered.
            autocmd User lsp_buffer_enabled call s:on_lsp_buffer_enabled()
        augroup END       
endfunction

function! s:on_lsp_buffer_enabled() abort
    setlocal omnifunc=lsp#complete
    setlocal signcolumn=yes
    nmap <buffer> gd <plug>(lsp-definition)
    nmap <buffer> <f2> <plug>(lsp-rename)
    " refer to doc to add more commands
endfunction

function! s:lsp_keymap() abort
    let g:space_keymap = get(g:, "space_keymap", { "name":"+space"})
    let g:space_keymap.L =  {   "name"  : "lsp" , 
                \   "c" :   {   "name"  : "+code",
                \               "a"     : ["<plug>(lsp-code-action)", "action"],
                \               "f"     : ["<plug>(lsp-code-action-float)", "float"],
                \               "p"     : ["<plug>(lsp-code-action-preview)", "preview"],
                \               "l"     : ["<plug>(lsp-code-lens)", "lens"]
                \           },
                \   "d" :   {   "name"  : "+document",
                \               "f"     : ["<plug>(lsp-document-format)",        "format"],
                \               "r"     : ["<plug>(lsp-document-range-format)",  "range"],
                \               "s"     : ["<plug>(lsp-document-symbol)",        "symbol"],
                \               "/"     : ["<plug>(lsp-document-symbol-search)", "search"],
                \               "d"     : ["<plug>(lsp-document-diagnostics)",   "diagnostics"],
                \           },
                \   "h" :   {   "name"  : "+hover",
                \               "h"     : ["<plug>(lsp-hover)", "hover"],
                \               "f"     : ["<plug>(lsp-hover-float)", "float"],
                \               "p"     : ["<plug>(lsp-hover-preview)", "preview"],
                \               "i"     : ["<plug>(lsp-call-hierarchy-incoming)", "incoming"],
                \               "o"     : ["<plug>(lsp-call-hierarchy-outgoing)", "outgoing"],
                \           },
                \   "n" :   {   "name"  : "+next",
                \               "d"     : ["<plug>(lsp-next-diagnostic)", "diagnostic"],
                \               "D"     : ["<plug>(lsp-next-diagnostic-nowrap)", "diagnostic-nowrap"],
                \               "e"     : ["<plug>(lsp-next-error)", "error"],
                \               "E"     : ["<plug>(lsp-next-error-nowrap)", "error-nowrap"],
                \               "r"     : ["<plug>(lsp-next-reference)", "reference"],
                \               "w"     : ["<plug>(lsp-next-warning)", "warning"],
                \               "W"     : ["<plug>(lsp-next-warning-nowrap)", "warning-nowrap"],
                \           },
                \   "p" :   {   "name"  : "+previous",
                \               "d"     : ["<plug>(lsp-previous-diagnostic)", "diagnostic"],
                \               "D"     : ["<plug>(lsp-previous-diagnostic-nowrap)", "diagnostic-nowrap"],
                \               "e"     : ["<plug>(lsp-previous-error)", "error"],
                \               "E"     : ["<plug>(lsp-previous-error-nowrap)", "error-nowrap"],
                \               "r"     : ["<plug>(lsp-previous-reference)", "reference"],
                \               "w"     : ["<plug>(lsp-previous-warning)", "warning"],
                \               "W"     : ["<plug>(lsp-previous-warning-nowrap)", "warning-nowrap"],
                \               "c"     : ["<plug>(lsp-preview-close)", "close"],
                \               "f"     : ["<plug>(lsp-preview-focus)", "focus"],
                \           },
                \   "k" :   {   "name"  : "+peek",
                \               "l"     : ["<plug>(lsp-declaration)", "declaration"],
                \               "L"     : ["<plug>(lsp-peek-declaration)", "peek-declaration"],
                \               "f"     : ["<plug>(lsp-definition)", "definition"],
                \               "F"     : ["<plug>(lsp-peek-definition)", "peek-definition"],
                \               "t"     : ["<plug>(lsp-type-definition)", "type-definition"],
                \               "T"     : ["<plug>(lsp-peek-type-definition)", "peek-type-definition"],
                \               "i"     : ["<plug>(lsp-implementation)", "implementation"],
                \               "I"     : ["<plug>(lsp-peek-implementation)", "peek-implementation"],
                \               "h"     : ["<plug>(lsp-type-hierarchy)", "type-hierarchy"],
                \               "H"     : ["<plug>(lsp-signature-help)", ""],
                \               "w"     : ["<plug>(lsp-workspace-symbol)", "workspace-symbol"],
                \               "W"     : ["<plug>(lsp-workspace-symbol-search)", "search"],
                \               "R"     : ["<plug>(lsp-rename)", "rename"],
                \               "r"     : ["<plug>(lsp-references)", "references"],
                \               "s"     : ["<plug>(lsp-status)", "status"]
                \           },
                \   "s" :   {   "name"  : "lsp-settings",
                \               "g"     : [":LspSettingsLocalEdit", "global"],
                \               "l"     : [":LspSettingsGlobalEdit", "local"],
                \               "s"     : [":LspSettingsStatus", "status"]
                \           }
                \ }
endfunction

function! s:vim_lsp_server() abort
    let g:vim_lsp_server_executable = globpath(g:lsp_settings_servers_dir, "vim-language-server/vim-language-server")
    let g:vim_lsp_server = {
                    \ 'name': 'vim-language-server',
                    \ 'cmd': {server_info->[g:vim_lsp_server_executable, '--node-ipc']},
                    \ 'whitelist': ['vim'],
                    \ 'blocklist': [],
                    \ 'config': {},
                    \ 'workspace_config': {},
                    \ 'languageId': {server_info->'vim'},
                    \ }
    if executable(g:vim_lsp_server_executable)
        au User lsp_setup call lsp#register_server(g:vim_lsp_server)
    endif
endfunction

function! s:python_lsp_server() abort
    if executable('pyls')
        " pip install python-language-server
        au User lsp_setup call lsp#register_server({
                    \ 'name': 'pyls',
                    \ 'cmd': {server_info->['pyls']},
                    \ 'whitelist': ['python'],
                    \ })
    endif
endfunction

function! api#lsp#init() abort
    if !exists('g:lsp_loaded')
        try
            packadd vim-lsp
            packadd vim-lsp-settings
        catch /.*/
            echoerr v:exception
        endtry
    endif
    if exists('g:lsp_loaded') && g:lsp_loaded
        call s:lsp_variables()
        call s:lsp_settings()
        call s:lsp_autocmds()
        call s:lsp_keymap()
        call s:python_lsp_server()
        call s:vim_lsp_server()
    endif
endfunction
